package com.oig.sys.workflow.app.impl;

import cn.hutool.http.HttpUtil;
import com.oig.common.exception.ServiceException;
import com.oig.common.util.JsonUtil;
import com.oig.sys.workflow.app.IAppFlowInstanceService;
import com.oig.sys.workflow.constants.FlowEnums;
import com.oig.sys.workflow.dto.ApprovalAgentReqDto;
import com.oig.sys.workflow.dto.ApprovalNotifyConDto;
import com.oig.sys.workflow.dto.FlowInstanceDto;
import com.oig.sys.workflow.flow.IDepFlowService;
import com.oig.sys.workflow.vo.InstanceAllInfoVo;
import com.oig.sys.workflow.service.ITbFlowConfigService;
import com.oig.sys.workflow.service.ITbFlowInstanceService;
import com.oig.sys.workflow.vo.ApprovalAgentRsp;
import com.oig.sys.workflow.vo.FlowConfigVo;
import com.oig.sys.workflow.vo.FlowInstanceVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

@Slf4j
@Component
@RequiredArgsConstructor
public class AppFlowInstanceServiceImpl implements IAppFlowInstanceService {

    private final ITbFlowConfigService flowConfigService;
    private final ITbFlowInstanceService flowInstanceService;
    private final IDepFlowService depFlowService;

    @Override
    public ApprovalAgentRsp apply(ApprovalAgentReqDto approvalAgentReqDto) {
        ApprovalAgentRsp rsp = new ApprovalAgentRsp();
        FlowConfigVo flowConfigVo = this.flowConfigService.getFlowConfigByBizType(approvalAgentReqDto.getBizType());
        if (flowConfigVo==null){
            rsp.setCode("0001");
            rsp.setResult("fail");
            rsp.setFailReason("业务对应的审批流未配置");
            return rsp;
        }
        FlowInstanceDto flowInstanceDto = new FlowInstanceDto();
        flowInstanceDto.setFlowConfigId(flowConfigVo.getId());
        flowInstanceDto.setSysCode(flowConfigVo.getSysCode());
        flowInstanceDto.setFlowCode(flowConfigVo.getFlowCode());
        flowInstanceDto.setFlowName(flowConfigVo.getFlowName());
        flowInstanceDto.setTenantId(flowConfigVo.getTenantId());
        flowInstanceDto.setTenantName(flowConfigVo.getTenantName());
        flowInstanceDto.setBizType(approvalAgentReqDto.getBizType());
        flowInstanceDto.setBizId(approvalAgentReqDto.getBizId());
        flowInstanceDto.setCreateUserCode(approvalAgentReqDto.getUserId());
        flowInstanceDto.setFlowData(approvalAgentReqDto.getApplyData());
        FlowInstanceVo flowInstanceVo;
        try {
            flowInstanceVo = this.flowInstanceService.addOrUpdate(flowInstanceDto);
        } catch (Exception e){
            log.error("存储审批单出错",e);
            rsp.setCode("0011");
            rsp.setResult("fail");
            rsp.setFailReason(e.getMessage());
            return rsp;
        }
        String instanceId = null ;
        try {
            instanceId = this.depFlowService.createInstance(flowConfigVo, flowInstanceVo);
            rsp.setCode("0000");
            rsp.setInstanceCode(instanceId);
            rsp.setResult("success");
        } catch (Exception e){
            log.error("提交审批出错",e);
            rsp.setCode("0031");
            rsp.setResult("fail");
            rsp.setFailReason(e.getMessage());
        }
        this.flowInstanceService.updateSubResult(flowInstanceVo.getId(), instanceId, rsp.getFailReason());
        return rsp;
    }

    @Override
    public InstanceAllInfoVo getDetail(ApprovalAgentReqDto approvalAgentReqDto) {
        FlowInstanceVo instanceVo = this.flowInstanceService.getFlowByBiz(approvalAgentReqDto.getBizType(),approvalAgentReqDto.getBizId());
        if (instanceVo==null||!FlowEnums.FlowStatus.PUSHED.getCode().equals(instanceVo.getStatus())){
            throw new ServiceException("未找到审批单，或是未提交或已撤销");
        }
        return this.depFlowService.getInstance(instanceVo.getFlowInstanceId(), approvalAgentReqDto.getUserId());
    }

    @Override
    public String cancel(ApprovalAgentReqDto approvalAgentReqDto) {
        FlowInstanceVo instanceVo = this.flowInstanceService.cancelFlowByBiz(approvalAgentReqDto.getBizType(),approvalAgentReqDto.getBizId());
        if (instanceVo==null){
            return "没有可撤销状态审批单" ;
        }
        if (FlowEnums.InstanceStatus.CANCELED.getCode().equals(instanceVo.getFlowInstanceStatus())){
            return "已撤销";
        } else if (FlowEnums.InstanceStatus.PENDING.getCode().equals(instanceVo.getFlowInstanceStatus())){
            try {
                depFlowService.cancelInstance(instanceVo.getFlowCode(), instanceVo.getFlowInstanceId(), approvalAgentReqDto.getUserId());
                flowInstanceService.doCancel(instanceVo.getId());
            } catch (Exception e){
                log.error("撤销异常", e);
                throw new ServiceException("撤销失败"+e.getMessage()) ;
            }
        }
        return "success";
    }


    @Override
    public void updateFlowInstanceStatus(String flowCode, String instanceId, String instanceStatus) {
        FlowInstanceVo flowInstanceVo = this.flowInstanceService.updateFlowInstanceStatus(flowCode, instanceId, instanceStatus);
        if (flowInstanceVo!=null && FlowEnums.NotifyStatus.PENDING.getCode().equals(flowInstanceVo.getNotifyStatus())){
            this.doNotify(flowInstanceVo);
        }
    }

    private void doNotify(FlowInstanceVo flowInstanceVo){
        //开启通知
        FlowConfigVo flowConfigVo = this.flowConfigService.getFlowConfig(flowInstanceVo.getFlowConfigId());
        String status = FlowEnums.NotifyStatus.UN_NEED.getCode();
        if (StringUtils.isNotBlank(flowConfigVo.getNotifyUrl())){
            ApprovalNotifyConDto notifyConDto = new ApprovalNotifyConDto();
            notifyConDto.setInstanceStatus(flowInstanceVo.getFlowInstanceStatus());
            notifyConDto.setBizType(flowInstanceVo.getBizType());
            notifyConDto.setBizId(flowInstanceVo.getBizId());
            log.debug("notify {}",notifyConDto);
            HttpUtil.post(flowConfigVo.getNotifyUrl(), JsonUtil.toJSONString(notifyConDto));
        }
        this.flowInstanceService.updateNotifyStatus(flowInstanceVo.getId(), status);
    }

    @Override
    public void notifyInstanceStatus(Integer id) {
        FlowInstanceVo flowInstanceVo = this.flowInstanceService.getById(id);
        this.doNotify(flowInstanceVo);
    }

}
